home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
nt
/
blat11.zip
/
BLAT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1994-12-08
|
21KB
|
784 lines
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
/* generic socket DLL support */
#include "gensock.h"
#ifdef WIN32
#define __far far
#define huge far
#define __near near
#endif
#define MAXOUTLINE 255
HANDLE gensock_lib = 0;
int (FAR PASCAL *pgensock_connect) (char FAR * hostname, char FAR * service, socktag FAR * pst);
int (FAR PASCAL *pgensock_getchar) (socktag st, int wait, char FAR * ch);
int (FAR PASCAL *pgensock_put_data) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL *pgensock_close) (socktag st);
int (FAR PASCAL *pgensock_gethostname) (char FAR * name, int namelen);
int (FAR PASCAL *pgensock_put_data_buffered) (socktag st, char FAR * data, unsigned long length);
int (FAR PASCAL *pgensock_put_data_flush) (socktag st);
socktag SMTPSock;
#define SERVER_SIZE 128 // #defines (bleah!) from Beverly Brown "beverly@datacube.com"
#define SENDER_SIZE 128
char SMTPHost[SERVER_SIZE];
char Sender[SENDER_SIZE];
char *Recipients;
char my_hostname[1024];
char *destination="";
char *cc_list="";
char *loginname="";
char *senderid="";
char *subject="";
char *usage[]= {
"Blat v1.1: WinNT console utility to mail a file to a user via SMTP",
"",
"syntax:",
"Blat <filename> [-s <subject>] -t <recipient> -f <address> [-i <address>]",
"Blat -SMTP <server address>",
"Blat -h",
"",
"-SMTP <server address> <senders address>: set's the address of the SMTP server to be used",
"",
"<filename>: the file with the message body",
"-s <subject>: the (optional) subject line",
"-t <recipient>: the recipient's address",
"-c <recipient>: the carbon copy recipient's address",
"-f <sender>: the sender's address (must be known to the SMTP server)",
"-i <address>: a 'From:' address, not necessarily known to the SMTP server.",
"-h: displays this help.",
"",
"Note that if the '-i' option is used, <sender> is included in 'Reply-to:'",
"and 'Sender:' fields in the header of the message."
};
const NMLINES=19;
void
gensock_error (char * function, int retval)
{
cout << "error " << retval << " in function '" << function;
}
// loads the GENSOCK DLL file
int load_gensock()
{
if( (gensock_lib = LoadLibrary("gensock.dll")) == NULL )
{
cout << "Couldn't load 'GENSOCK.DLL'\n";
return -1;
}
if(
( pgensock_connect =
( int (FAR PASCAL *)(char FAR *, char FAR *, socktag FAR *) )
GetProcAddress(gensock_lib, "gensock_connect")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_connect\n";
return -1;
}
if (
( pgensock_getchar =
( int (FAR PASCAL *) (socktag, int, char FAR *) )
GetProcAddress(gensock_lib, "gensock_getchar")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_getchar\n";
return -1;
}
if(
( pgensock_put_data =
( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
GetProcAddress(gensock_lib, "gensock_put_data")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_put_data\n";
return -1;
}
if(
( pgensock_close =
(int (FAR PASCAL *) (socktag) )
GetProcAddress(gensock_lib, "gensock_close")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_close\n";
return -1;
}
if(
( pgensock_gethostname =
(int (FAR PASCAL *) (char FAR *, int) )
GetProcAddress(gensock_lib, "gensock_gethostname")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_gethostname\n";
return -1;
}
if(
( pgensock_put_data_buffered =
( int (FAR PASCAL *) (socktag, char FAR *, unsigned long) )
GetProcAddress(gensock_lib, "gensock_put_data_buffered")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_put_data_buffered\n";
return -1;
}
if(
( pgensock_put_data_flush =
( int (FAR PASCAL *) (socktag) )
GetProcAddress(gensock_lib, "gensock_put_data_flush")
) == NULL
)
{
cout << "couldn't getprocaddress for gensock_put_data_flush\n";
return -1;
}
return 0;
}
int open_smtp_socket( void )
{
int retval;
/* load the library if it's not loaded */
// if (!gensock_lib)
if ( ( retval = load_gensock() ) ) return ( retval );
if ( (retval = (*pgensock_connect) ((LPSTR) SMTPHost,
(LPSTR)"smtp",
&SMTPSock)))
{
if (retval == ERR_CANT_RESOLVE_SERVICE)
{
if ((retval = (*pgensock_connect) ((LPSTR)SMTPHost,
(LPSTR)"25",
&SMTPSock)))
{
gensock_error ("gensock_connect", retval);
return -1;
}
}
// error other than can't resolve service
else
{
gensock_error ("gensock_connect", retval);
return -1;
}
}
// we wait to do this until here because WINSOCK is
// guaranteed to be already initialized at this point.
// get the local hostname (needed by SMTP)
if ((retval = (*pgensock_gethostname) (my_hostname, sizeof(my_hostname))))
{
gensock_error ("gensock_gethostname", retval);
return -1;
}
// strcpy( my_hostname, "pcfchb.dbs.aber.ac.uk");
return 0;
}
int close_smtp_socket( void )
{
int retval;
if( (retval = (*pgensock_close) (SMTPSock)) )
{
gensock_error ("gensock_close", retval);
return -1;
}
FreeLibrary( gensock_lib );
return (0);
}
int get_smtp_line( void )
{
char ch = '.';
char in_data [MAXOUTLINE];
char * index;
int retval = 0;
index = in_data;
while (ch != '\n')
{
if( (retval = (*pgensock_getchar) (SMTPSock, 0, &ch) ) )
{
gensock_error ("gensock_getchar", retval);
return -1;
}
else
{
*index = ch;
index++;
}
}
/* this is to support multi-line responses, common with */
/* servers that speak ESMTP */
/* I know, I know, it's a hack 8^) */
if( in_data[3] == '-' ) return( get_smtp_line() );
else return atoi(in_data);
}
int put_smtp_line( socktag sock, char far * line, unsigned int nchars )
{
int retval;
if( (retval = (*pgensock_put_data) (sock, line, (unsigned long) nchars)))
{
gensock_error ("gensock_put_data", retval);
return -1;
}
return (0);
}
int putline_internal (socktag sock, char * line, unsigned int nchars)
{
int retval;
if ((retval =
(*pgensock_put_data) (sock,
(char FAR *) line,
(unsigned long) nchars)))
{
switch (retval)
{
case ERR_NOT_CONNECTED:
gensock_error( "SMTP server has closed the connection", retval );
break;
default:
gensock_error ("gensock_put_data", retval);
}
return -1;
}
return (0);
}
void smtp_error (char * message)
{
cout << message << "\n";
put_smtp_line (SMTPSock, "QUIT\r\n", 6);
close_smtp_socket();
}
// 'destination' is the address the message is to be sent to
// 'message' is a pointer to a null-terminated 'string' containing the
// entire text of the message.
int prepare_smtp_message(char * MailAddress, char * destination)
{
char out_data[MAXOUTLINE];
char str[1024];
char *ptr;
int len, startLen;
if ( open_smtp_socket() ) return -1;
if ( get_smtp_line() != 220 )
{
smtp_error ("SMTP server error");
return(-1);
}
sprintf( out_data, "HELO %s\r\n", my_hostname );
put_smtp_line( SMTPSock, out_data, strlen (out_data) );
if ( get_smtp_line() != 250 )
{
smtp_error ("SMTP server error");
return -1;
}
sprintf (out_data, "MAIL From:<%s>\r\n", loginname);
put_smtp_line( SMTPSock, out_data, strlen (out_data) );
if (get_smtp_line() != 250)
{
smtp_error ("The mail server doesn't like the sender name,\nhave you set your mail address correctly?");
return -1;
}
// do a series of RCPT lines for each name in address line
for (ptr = destination; *ptr; ptr += len + 1)
{
// if there's only one token left, then len will = startLen,
// and we'll iterate once only
startLen = strlen (ptr);
if ((len = strcspn (ptr, " ,\n\t\r")) != startLen)
{
ptr[len] = '\0'; // replace delim with NULL char
while (strchr (" ,\n\t\r", ptr[len+1])) // eat white space
ptr[len++] = '\0';
}
sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
putline_internal( SMTPSock, out_data, strlen (out_data) );
if (get_smtp_line() != 250)
{
sprintf (str, "The mail server doesn't like the name %s.\nHave you set the 'To: ' field correctly?", ptr);
smtp_error (str);
return -1;
}
if (len == startLen) // last token, we're done
break;
}
sprintf (out_data, "DATA\r\n");
put_smtp_line (SMTPSock, out_data, strlen (out_data));
if (get_smtp_line() != 354)
{
smtp_error ("Mail server error accepting message data");
return -1;
}
return(0);
}
int transform_and_send_edit_data( socktag sock, char * editptr )
{
char *index;
char *header_end;
char previous_char = 'x';
unsigned int send_len;
int retval;
BOOL done = 0;
send_len = lstrlen(editptr);
index = editptr;
header_end = strstr (editptr, "\r\n\r\n");
while (!done)
{
// room for extra char for double dot on end case
while ((unsigned int) (index - editptr) < send_len)
{
switch (*index)
{
case '.':
if (previous_char == '\n')
/* send _two_ dots... */
if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) return (retval);
if ((retval = (*pgensock_put_data_buffered) (sock, index, 1))) return (retval);
break;
case '\r':
// watch for soft-breaks in the header, and ignore them
if (index < header_end && (strncmp (index, "\r\r\n", 3) == 0))
index += 2;
else
if (previous_char != '\r')
if ((retval = (*pgensock_put_data_buffered) (sock, index, 1)))
return (retval);
// soft line-break (see EM_FMTLINES), skip extra CR */
break;
default:
if ((retval = (*pgensock_put_data_buffered) (sock, index, 1)))
return (retval);
}
previous_char = *index;
index++;
}
if( (unsigned int) (index - editptr) == send_len) done = 1;
}
// this handles the case where the user doesn't end the last
// line with a <return>
if (editptr[send_len-1] != '\n')
{
if ((retval = (*pgensock_put_data_buffered) (sock, "\r\n.\r\n", 5)))
return (retval);
}
else
if ((retval = (*pgensock_put_data_buffered) (sock, ".\r\n", 3)))
return (retval);
/* now make sure it's all sent... */
if ((retval = (*pgensock_put_data_flush)(sock))) return (retval);
return (TRUE);
}
int send_smtp_edit_data (char * message)
{
transform_and_send_edit_data( SMTPSock, message );
if (get_smtp_line() != 250)
{
smtp_error ("Message not accepted by server");
return -1;
}
return(0);
}
int finish_smtp_message( void )
{
return put_smtp_line( SMTPSock, "QUIT\r\n", 6 );
}
// create a registry entries for this program
int CreateRegEntry( void )
{
HKEY hKey1;
DWORD dwDisposition;
LONG lRetCode;
/* try to create the .INI file key */
lRetCode = RegCreateKeyEx ( HKEY_CURRENT_USER,
"SOFTWARE\\Public Domain\\Blat",
0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,NULL, &hKey1,&dwDisposition
);
/* if we failed, note it, and leave */
if (lRetCode != ERROR_SUCCESS)
{
printf ("Error in creating blat key in the registry\n");
return 10;
}
/* try to set a section value */
lRetCode = RegSetValueEx( hKey1,"SMTP server",0,REG_SZ, (BYTE *) &SMTPHost[0], (strlen(SMTPHost)+1));
/* if we failed, note it, and leave */
if (lRetCode != ERROR_SUCCESS)
{
printf ( "Error in setting SMTP server value in the registry\n");
return 11;
}
/* try to set another section value */
lRetCode = RegSetValueEx( hKey1,"Sender",0,REG_SZ, (BYTE *) &Sender[0], (strlen(Sender)+1));
/* if we failed, note it, and leave */
if (lRetCode != ERROR_SUCCESS)
{
printf ( "Error in setting sender address value in the registry\n");
return 11;
}
return 0;
}
// get the registry entries for this program
int GetRegEntry( void )
{
HKEY hKey1;
DWORD dwType;
DWORD dwBytesRead;
LONG lRetCode;
// open the registry key in read mode
lRetCode = RegOpenKeyEx( HKEY_CURRENT_USER,
"SOFTWARE\\Public Domain\\Blat",
0, KEY_READ, &hKey1
);
// set the size of the buffer to contain the data returned from the registry
// thanks to Beverly Brown "beverly@datacube.com" and "chick@cyberspace.com" for spotting it...
dwBytesRead=SERVER_SIZE;
// read the value of the SMTP server entry
lRetCode = RegQueryValueEx( hKey1, "SMTP server", NULL , &dwType, (BYTE *) &SMTPHost, &dwBytesRead);
// if we failed, note it, and leave
if( lRetCode != ERROR_SUCCESS )
{
printf( "Error in reading SMTP server value from the registry\n" );
return 12;
}
// read the value of the SMTP server entry
lRetCode = RegQueryValueEx( hKey1, "Sender", NULL , &dwType, (BYTE *) &Sender, &dwBytesRead);
// if we failed, note it, and leave
if( lRetCode != ERROR_SUCCESS )
{
printf( "Error in reading senders user name from the registry\n" );
return 12;
}
return 0;
}
int main( int argc, /* Number of strings in array argv */
char *argv[], /* Array of command-line argument strings */
char **envp ) /* Array of environment variable strings */
{
int next_arg=2;
int impersonating = 0;
// get file name from argv[1]
char *filename=argv[1];
if(argc<2)
{
// must have at least file name to send
for(int i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
return 1;
}
senderid = Sender;
loginname = Sender;
// thanks to Beverly Brown "beverly@datacube.com" for
// fixing the argument parsing, I "fixed" the brackets
// to conform approximately to our "style" :-)
// Starts here
for(next_arg=1;next_arg < argc;next_arg++)
{
if(lstrcmpi("-h",argv[next_arg])==0)
{
for(int i=0;i<NMLINES;i++) cout<<usage[i]<<'\n';
return 1;
}
// is argv[2] "-SMTP"? If so, indicate error and return
else if(lstrcmpi("-SMTP",argv[next_arg])==0)
{
if((argc == 3) || (argc == 4))
{
strcpy( SMTPHost, argv[++next_arg] );
if(argc == 4)
strcpy( Sender, argv[++next_arg] );
else
strcpy( Sender, "" );
if( CreateRegEntry() == 0 )
{
printf("\nSMTP server set to %s\n", SMTPHost );
return 0;
}
}
else
{
printf( "to set the SMTP server's address and the user name at that address do:\nblat -SMTP server username");
return 6;
}
}
// is argv[2] "-s"? If so, argv[3] is the subject
else if(lstrcmpi("-s",argv[next_arg])==0)
{
subject=argv[++next_arg];
}
// is argv[2] "-c"? If so, argv[3] is the carbon-copy list
else if(lstrcmpi("-c",argv[next_arg])==0)
{
cc_list=argv[++next_arg];
}
// is next argv "-t"? If so, succeeding argv is the destination
else if(lstrcmpi("-t",argv[next_arg])==0)
{
destination=argv[++next_arg];
}
//is next argv '-f'? If so, succeeding argv is the loginname
else if(lstrcmp("-f",argv[next_arg])==0)
{
loginname=argv[++next_arg];
if( ! impersonating )
senderid = loginname;
}
//is next argv '-i'? If so, succeeding argv is the sender id
else if(lstrcmp("-i",argv[next_arg])==0)
{
senderid=argv[++next_arg];
impersonating = 1;
}
else if(next_arg == 1)
{
OFSTRUCT of;
if(lstrlen(filename)<=0 ||
OpenFile(filename,&of,OF_EXIST)
==HFILE_ERROR)
{
cout<<filename<<" does not exist\n";
return 2;
}
}
else
{
for(int i=0;i<NMLINES;i++)
cout<<usage[i]<<'\n';
return 1;
}
}
// fixing the argument parsing
// Ends here
if( GetRegEntry() )
{
printf( "to set the SMTP server's address and the user name at that address do:\nblat -SMTP server username\n");
printf( "aborting, nothing sent\n" );
return 12;
}
// make sure filename exists, get full pathname
OFSTRUCT of;
if(lstrlen(filename)<=0 || OpenFile(filename,&of,OF_EXIST)==HFILE_ERROR)
{
cout<<filename<<" does not exist\n";
return 2;
}
// build the recipients list
Recipients = new char [ strlen(destination) + strlen(cc_list) + 2 ];
strcpy( Recipients, destination );
if( strlen(cc_list) > 0 )
{
strcat(Recipients, "," );
strcat(Recipients, cc_list );
}
// create a header for the message
char tmpstr[256];
char header[1024];
int headerlen;
SYSTEMTIME curtime;
TIME_ZONE_INFORMATION tzinfo;
char * days[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
char * months[] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
DWORD retval;
GetLocalTime( &curtime );
retval = GetTimeZoneInformation( &tzinfo );
// rfc1036&rfc822 acceptable format
// Mon, 29 Jun 94 02:15:23 GMT
sprintf (tmpstr, "Date: %s, %.2d %s %.2d %.2d:%.2d:%.2d ",
days[curtime.wDayOfWeek],
curtime.wDay,
months[curtime.wMonth - 1],
curtime.wYear,
curtime.wHour,
curtime.wMinute,
curtime.wSecond);
strcpy( header, tmpstr );
for(int i=0;i<32;i++)
{
if( retval == TIME_ZONE_ID_STANDARD ) tmpstr[i] = (char) tzinfo.StandardName[i];
else tmpstr[i] = (char) tzinfo.DaylightName[i];
}
strcat( header, tmpstr );
strcat( header, "\r\n" );
sprintf( tmpstr, "From: %s\r\n", senderid );
strcat( header, tmpstr );
if( impersonating )
{
sprintf( tmpstr, "Sender: %s\r\n", loginname );
strcat( header, tmpstr );
sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
strcat( header, tmpstr );
}
if( *subject )
{
sprintf( tmpstr, "Subject: %s\r\n", subject );
strcat( header, tmpstr );
}
else
{
sprintf( tmpstr, "Subject: Contents of file: %s\r\n", filename );
strcat( header, tmpstr );
}
sprintf( tmpstr, "To: %s\r\n", destination );
strcat( header, tmpstr );
if( *cc_list )
{
// Add line for the Carbon Copies
sprintf( tmpstr, "Cc: %s\r\n", cc_list );
strcat( header, tmpstr );
}
strcat( header, "X-Mailer: <WinNT's Blat ver 1.1>\r\n" );
strcat( header, "\r\n" );
headerlen = strlen( header );
//get the text of the file into a string buffer
HANDLE fileh;
if((fileh=CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,NULL))==INVALID_HANDLE_VALUE)
{
cout<<"error reading "<<filename<<", aborting\n";
delete [] Recipients;
return 3;
}
if(GetFileType(fileh)!=FILE_TYPE_DISK)
{
cout<<"Sorry, I can only mail messages from disk files...\n";
delete [] Recipients;
return 4;
}
DWORD filesize = GetFileSize( fileh,NULL );
char *buffer = new char[filesize+headerlen+1];
char *tmpptr;
// put the header at the top...
strcpy( buffer, header );
// point to the end of the header
tmpptr = buffer + headerlen;
// and put the whole file there
DWORD dummy;
if(!ReadFile(fileh,tmpptr,filesize,&dummy,NULL))
{
cout<<"error reading "<<filename<<", aborting\n";
CloseHandle(fileh);
delete [] buffer;
delete [] Recipients;
return 5;
}
CloseHandle(fileh);
cout<<"Sending "<<filename<<" to "<<(lstrlen(Recipients)?
Recipients:"<unspecified>")<<'\n';
if(lstrlen(subject))
cout<<"Subject:"<<subject<<'\n';
if(lstrlen(loginname))
cout<<"Login name is "<<loginname<<'\n';
if( !prepare_smtp_message( loginname, Recipients ) )
{
if( !send_smtp_edit_data( buffer ) )
finish_smtp_message();
close_smtp_socket();
}
delete [] buffer;
delete [] Recipients;
return 0;
}